package com.cictec.middleware.gps.engine.thread;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;

import javax.annotation.PostConstruct;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.cictec.middleware.commons.utils.Constants;
import com.cictec.middleware.commons.utils.DateUtils;
import com.cictec.middleware.commons.utils.PropertiesUtils;
import com.cictec.middleware.commons.utils.log.MultiLog;
import com.cictec.middleware.commons.utils.log.MultiLogUtils;
import com.cictec.middleware.core.pojo.MiddlewarePosition;
import com.cictec.middleware.gps.engine.TimeEventBus;
import com.cictec.middleware.gps.engine.TimingObject;

@Component
public class PointExecutorManager {

	private static Logger logger = LoggerFactory.getLogger(PointExecutorManager.class);
	@Autowired
	private TimeEventBus timeEventBus;
	private int maxSize = 20;
	private int executorCount = 0;

	private List<PointExecutor> pointExecutorList = new ArrayList<PointExecutor>();

	public PointExecutorManager() {
	}

	public PointExecutorManager(int maxSize) {
		this.maxSize = maxSize;
	}

	public PointExecutorManager(TimeEventBus timeEventBus, int maxSize) {
		this.maxSize = maxSize;
		this.timeEventBus = timeEventBus;
	}

	@PostConstruct
	public void init() {

		this.maxSize = PropertiesUtils.getIntValue("system.parameter.pointpool.maxConsumer", 30);
		logger.debug("【PointExecutorManager】初始化位置事件执行线程池,每个工作线程执行 {} 个设备", maxSize);

		new Thread() {
			public void run() {
				while (true) {
					monitor();
				}
			}
		}.start();
	}

	/**
	 * 调用执行器执行业务逻辑
	 * @param position
	 */
	public void execute(MiddlewarePosition position) {

		try {
			String devcode = position.getDevCode();
			PointExecutor executor = getPointExecutor(devcode);
			executor.execute(position);
		} catch (Exception e) {
			e.printStackTrace();

			logger.error("【PointExecutorManager】 位置信息逻辑判定报错 {}", e);
		}
	}

	/**
	 * 调用执行器执行业务逻辑
	 * 
	 * @param timingObject
	 */
	public void execute(TimingObject timingObject) {

		try {
			String devcode = timingObject.getAttribute(Constants.HED_DEV_CODE);
			PointExecutor executor = getPointExecutor(devcode);
			executor.execute(timingObject);
		} catch (Exception e) {
			e.printStackTrace();

			logger.error("【PointExecutorManager】 位置信息逻辑判定报错 {}", e);
		}
	}

	/**
	 * 关闭线程池
	 */
	public void shutdown() {
		for (PointExecutor pointExecutor : pointExecutorList) {
			pointExecutor.shutdown();
		}
	}

	/**
	 * 根据设备编号获取对应的执行器
	 * 
	 * @param devcode
	 * @return
	 */
	private PointExecutor getPointExecutor(String devcode) {
		PointExecutor executor = null;
		// 判定现有线程池是否已经存在该devcode
		for (PointExecutor pointExecutor : pointExecutorList) {
			if (pointExecutor.contains(devcode)) {
				return pointExecutor;
			}
		}

		// 获取未满的线程池
		for (PointExecutor pointExecutor : pointExecutorList) {

			if (!pointExecutor.isMaxDispatcher()) {
				pointExecutor.addDevcode(devcode);
				return pointExecutor;
			}
		}

		String threadName = "bus-position-caculate-" + (executorCount + 1);
		// executor = new PointExecutor(timeEventBus, maxSize,
		// Executors.newFixedThreadPool(1, getThreadFactory(threadName)));
		ThreadPoolExecutor pool = (ThreadPoolExecutor) Executors.newFixedThreadPool(1, getThreadFactory(threadName));
		executor = new PointExecutor(timeEventBus, maxSize, pool, threadName);
		executor.addDevcode(devcode);
		pointExecutorList.add(executor);
		executorCount++;

		return executor;
	}

	public List<PointExecutor> getPointExecutorList() {
		return pointExecutorList;
	}

	private void monitor() {

		String logPath = "monitor/" + DateUtils.formatDate(new Date()) + "monitor";
		logPath += ",monitor";
		MultiLog log = MultiLogUtils.getMultiLog(logPath);

		int count = 0;
		for (PointExecutor pointExecutor : pointExecutorList) {

			ThreadPoolExecutor pool = pointExecutor.getExecutor();
			log.debug(
					"[monitor] {} [{}/{}] Active:{}, Completed:{}, Task:{}, queueSize:{}, isShutdown:{}, isTerminated:{}, devCode:{}",
					"pool-" + count, pool.getPoolSize(), pool.getCorePoolSize(), pool.getActiveCount(),
					pool.getCompletedTaskCount(), pool.getTaskCount(), pool.getQueue().size(), pool.isShutdown(),
					pool.isTerminated(), pointExecutor.getDevice());
			count++;

		}

		int seconds = 5;
		try {
			Thread.sleep(seconds * 1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	private ThreadFactory getThreadFactory(String threadName) {
		return new ThreadFactory() {
			// AtomicInteger sn = new AtomicInteger();

			public Thread newThread(Runnable r) {
				SecurityManager s = System.getSecurityManager();
				ThreadGroup group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
				Thread t = new Thread(group, r);
				t.setName(threadName);
				// t.setName("point-execute-thread-" + sn.incrementAndGet());
				return t;
			}
		};
	}
}
